import asyncio
import json
import logging
from datetime import datetime, timedelta
from fastapi import APIRouter,WebSocket
import time
from sqlalchemy import text
from starlette.websockets import WebSocketDisconnect
from Model.SqlDef.logindata import kill_illeagl_time, updata_time_span, get_time_long_data, updata_time
from Model.default import SessionLocal
from Model.user.User import time_week, user_time_behavior, time_active_span, user_expand, user
from config.user import WEEKDAY_
from func.date import deal_current_weekday_start_end, are_in_same_week, deal_time_span

mysocket_logindata=APIRouter(prefix='/date_socket',tags=['date_socket'])

# 处理所有时间段
def updata_all_time_span(day,span,user_id):
    session = SessionLocal()
    try:
        middle=session.query(time_week).filter_by(user_id=user_id).order_by(time_week.id.desc()).first()
        if middle is not  None:
            (start_timestamp, end_timestamp), week_timestamps = deal_current_weekday_start_end()
            week_data=time_week(user_id=user_id,d_mon=start_timestamp,d_sun=end_timestamp)
            session.add(week_data)
            session.commit()
        table = 'time_week'
        update_stmt = text(f"UPDATE {table} SET {day} = {span} WHERE id={id}")
        session.execute(update_stmt, {'id': id})
        session.commit()

    except Exception as e:
        session.rollback()

    finally:
        session.close()

# 登录时处理login时长
def deal_login_time(user_id):

    session = SessionLocal()

    try:
        # 改变用户在线状态,这个和用户主动作用是不一致的。
        session.query(user_expand).filter_by(id=user_id).first().isonline=1

        (start_timestamp, end_timestamp),week_timestamps=deal_current_weekday_start_end()
        user_behavior = session.query(user_time_behavior).filter_by(user_id=user_id).first()
        user_behavior_data={key: value for key, value in vars(user_behavior).items() if not key.startswith('_')} #每个字段数据

        # 清除非本周数据：时间
        # 由于数据储存信息，不直接适用遍历
        for i in WEEKDAY_:
            if user_behavior_data.get(i) is not None:
                if start_timestamp<=int(json.loads(user_behavior_data.get(i)).get('logout'))<=end_timestamp:
                        pass
                else:

                    kill_illeagl_time(i,user_id)

        current_Date=int(datetime.now().timestamp())
        # 处理所有周时间记录
        if user_behavior.last_login:
            if are_in_same_week(int(user_behavior.last_login),current_Date):
               pass
            else:
                manager.along=False
                count=session.query(user_time_behavior).filter_by(user_id=user_id).first()
                count.k_default=0
                count.k_diary=0
                count.k_food=0
                count.k_life=0

        user_behavior.last_login=current_Date
        # 处理时段分析
        if session.query(time_active_span).filter_by(user_id=user_id).first():
            pass
        else:
            middleobj=time_active_span(user_id=user_id)
            session.add(middleobj)
            session.commit()
            time.sleep(2)

        updata_time_span(deal_time_span(datetime.now().hour), user_id)


        session.commit()

    except  Exception as e:

        print(e)
        session.rollback()

    finally:
        session.close()


# 处理所有周时长
def deal_all_week_span(day,user_id):
    (start_timestamp, end_timestamp), week_timestamps = deal_current_weekday_start_end()
    session = SessionLocal()
    try:
        if manager.along:
            pass
        else:
            week_data=time_week(user_id=user_id,d_mon=start_timestamp,d_sun=end_timestamp)
            session.add(week_data)
            session.commit()
    except:
        session.rollback()
    finally:
        session.close()
        if get_time_long_data(day, user_id):
            updata_all_time_span(day, json.loads(get_time_long_data(day, user_id)).get('long'), user_id)
        else:
            updata_all_time_span(day,None, user_id)

# 处理时长 ,可优化，先同周处理更好
def deal_shutdown_time(user_id):

    session = SessionLocal()
    session.query(user).filter_by(id=user_id).first().isonline=0
    (start_timestamp, end_timestamp), week_timestamps = deal_current_weekday_start_end()
    current_Date = int(datetime.now().timestamp())
    user_behavior = session.query(user_time_behavior).filter_by(user_id=user_id).first()
    if user_behavior is None:
        behavior=user_time_behavior(user_id=user_id)
        behavior.last_login=current_Date
        session.add(behavior)
        session.commit()
    else:
        login_date = int(user_behavior.last_login)
        day = datetime.fromtimestamp(login_date).weekday()
        s_day = WEEKDAY_[day]
        try:
            # 分类更新时长
            if datetime.fromtimestamp(login_date).date()==datetime.fromtimestamp(current_Date).date():
                        #判断为同一天
                if get_time_long_data(s_day,user_id)!=None:
                    updata_time(s_day,user_id,current_Date,
                            json.loads(get_time_long_data(s_day,user_id)).get('long')+(current_Date-login_date))
                else:
                    updata_time(s_day, user_id, current_Date,(current_Date-login_date))

            else:
                if are_in_same_week(current_Date, login_date):
                        #判断为非同一天的同一周
                        dt_object = datetime.fromtimestamp(week_timestamps.get(s_day))
                        dt_object += timedelta(days=1)
                        new_timestamp = int(dt_object.timestamp())
                        updata_time(s_day, user_id, current_Date,(new_timestamp - login_date))
                        updata_time(s_day, user_id, current_Date,(current_Date - new_timestamp))
                else:
                        #判断为非同一天非同周,先清空数据
                        for i in WEEKDAY_:

                            kill_illeagl_time(i,user_id)
                        updata_time(s_day,user_id,current_Date,current_Date-week_timestamps.get('s_day'))
        except Exception as e:
            pass
        finally:
            session.close()
            deal_all_week_span(s_day, user_id)



class ConnectionManager:
    # 需要保持连接
    def __init__(self):
        self.active_connections: list[WebSocket] = []
        self.along = True  # 你的原有业务标志

    async def connect(self, websocket: WebSocket):
        """接受并记录新连接"""
        await websocket.accept()
        self.active_connections.append(websocket)
        logging.info(f"新连接建立，当前连接数: {len(self.active_connections)}")

    def disconnect(self, websocket: WebSocket,id):
        """安全断开连接"""
        try:
            if websocket in self.active_connections:
                self.active_connections.remove(websocket)
                logging.info(f"连接断开，剩余连接数: {len(self.active_connections)}")
                # 执行你的断开处理逻辑
                if websocket:
                    try:
                        deal_shutdown_time(id)
                    except Exception as e:
                        logging.error(f"处理断开时间失败: {e}")
                    finally:
                        pass
        except Exception as e:
            logging.error(f"断开连接时出错: {e}")
        finally:
            logging.info("断开连接逻辑结束")

    def user_login(self,id):
        """处理用户登录逻辑"""
        if  id=='null' or id==None:
            return
        try:
            deal_login_time(id)
        except Exception as e:
            logging.error(f"处理登录时间失败: {e}")

    async def check_connection(self, websocket: WebSocket,id) -> bool:
        """检查连接是否仍然有效"""
        try:
            if websocket not in self.active_connections:
                return False

            # 使用 Ping 帧检测连接状态
            await websocket.send_text("ping")  # 发送心跳包
            return True
        except Exception as e:
            logging.error(f"心跳检测失败: {e}")
            self.disconnect(websocket,id)
            return False


manager = ConnectionManager()

@mysocket_logindata.websocket("/ws/{id}")
async def websocket_endpoint(id:int,websocket: WebSocket):
    await manager.connect(websocket)
    try:
        while True:
            try:
                data = await asyncio.wait_for(
                    websocket.receive_text(),
                    timeout=25
                )
                if data == "ping":
                    # 如果接收到的是心跳包，回复 pong
                    await websocket.send_text("pong")
                else:
                    # 处理用户数据
                    manager.user_login(id)

            except asyncio.TimeoutError:
                # 心跳检测
                if not await manager.check_connection(websocket,id):
                    break
                continue
            except RuntimeError as e:
                if "WebSocket connection is closed" in str(e):
                    break
                raise
    except WebSocketDisconnect:
        logging.info("客户端主动断开连接")
    except Exception as e:
        logging.error(f"WebSocket错误: {type(e).__name__}: {e}")
    finally:
        manager.disconnect(websocket,id)
        logging.info("连接清理完成")












